/*
    SUSAN® - Sole of Unix Save ANything

      Copyright (C) 2011-2016 Skyatlas Co. LTD

   Copyright (C) 2013-2013 Hechzh Property

   
*/

/*
 *  Marco van Wieringen, May 2012
 */

#include "include/susan.h"

#ifdef HAVE_POLL_H
#include <poll.h>
#elif HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif

#ifdef HAVE_POLL
/*
 *   Returns: 1 if data available
 *            0 if timeout
 *           -1 if error
 */
int WaitForReadableFd(int fd, int msec, bool ignore_interupts)
{
  struct pollfd pfds[1];
  int events;

  events = POLLIN;
#if defined(POLLRDNORM)
  events |= POLLRDNORM;
#endif
#if defined(POLLRDBAND)
  events |= POLLRDBAND;
#endif
#if defined(POLLPRI)
  events |= POLLPRI;
#endif

  memset(pfds, 0, sizeof(pfds));
  pfds[0].fd = fd;
  pfds[0].events = events;

  for (;;) {
    switch (poll(pfds, 1, msec)) {
      case 0: /* timeout */
        return 0;
      case -1:
        if (ignore_interupts && (errno == EINTR || errno == EAGAIN)) {
          continue;
        }
        return -1; /* error return */
      default:
        if (pfds[0].revents & events) {
          return 1;
        } else {
          return 0;
        }
    }
  }
}

/*
 *   Returns: 1 if data available
 *            0 if timeout
 *           -1 if error
 */
int WaitForWritableFd(int fd, int msec, bool ignore_interupts)
{
  struct pollfd pfds[1];
  int events;

  events = POLLOUT;
#if defined(POLLWRNORM)
  events |= POLLWRNORM;
#endif
#if defined POLLWRBAND
  events |= POLLWRBAND;
#endif

  memset(pfds, 0, sizeof(pfds));
  pfds[0].fd = fd;
  pfds[0].events = events;

  for (;;) {
    switch (poll(pfds, 1, msec)) {
      case 0: /* timeout */
        return 0;
      case -1:
        if (ignore_interupts && (errno == EINTR || errno == EAGAIN)) {
          continue;
        }
        return -1; /* error return */
      default:
        if (pfds[0].revents & events) {
          return 1;
        } else {
          return 0;
        }
    }
  }
}
#else
/*
 *   Returns: 1 if data available
 *            0 if timeout
 *           -1 if error
 */
int WaitForReadableFd(int fd, int msec, bool ignore_interupts)
{
  fd_set fdset;
  struct timeval tv;

  tv.tv_sec = msec / 1000;
  tv.tv_usec = (msec % 1000) * 1000;

  for (;;) {
    FD_ZERO(&fdset);
    FD_SET((unsigned)fd, &fdset);
    switch (select(fd + 1, &fdset, NULL, NULL, &tv)) {
      case 0: /* timeout */
        return 0;
      case -1:
        if (ignore_interupts && (errno == EINTR || errno == EAGAIN)) {
          continue;
        }
        return -1; /* error return */
      default:
        return 1;
    }
  }
}

/*
 *   Returns: 1 if data available
 *            0 if timeout
 *           -1 if error
 */
int WaitForWritableFd(int fd, int msec, bool ignore_interupts)
{
#if defined(HAVE_WIN32)
  return 1;
#else
  fd_set fdset;
  struct timeval tv;

  tv.tv_sec = msec / 1000;
  tv.tv_usec = (msec % 1000) * 1000;

  for (;;) {
    FD_ZERO(&fdset);
    FD_SET((unsigned)fd, &fdset);
    switch (select(fd + 1, NULL, &fdset, NULL, &tv)) {
      case 0: /* timeout */
        return 0;
      case -1:
        if (ignore_interupts && (errno == EINTR || errno == EAGAIN)) {
          continue;
        }
        return -1; /* error return */
      default:
        return 1;
    }
  }
#endif /* defined(HAVE_WIN32) */
}
#endif /* HAVE_POLL */
